import os
import subprocess
import time

from django.core.exceptions import ObjectDoesNotExist
from django.db import DataError
from django.db.models import Q
from django.utils.decorators import method_decorator
from rest_framework.permissions import DjangoModelPermissions
from rest_framework.response import Response
from rest_framework.viewsets import GenericViewSet

from FasterRunner.settings import MEDIA_ROOT
from fastrunner import models, serializers
from fastrunner.utils import response
from fastrunner.utils.decorator import request_log
from fastrunner.utils.parse_api_data import import_api_data
from fastrunner.utils.parser import Format, Parse
from fastrunner.utils.permissions import IsBelongToProject
from fastrunner.utils.prepare import api_end


class APITemplateView(GenericViewSet):
    """
    API操作视图
    """
    serializer_class = serializers.APISerializer
    queryset = models.API.objects
    permission_classes = (DjangoModelPermissions, IsBelongToProject)

    @method_decorator(request_log(level='INFO'))
    def list(self, request):
        """
        接口列表 {
            project: int,
            node: int
        }
        """

        node = request.query_params["node"]
        project = request.query_params["project"]
        search = request.query_params["search"]
        queryset = self.get_queryset().filter(project__id=project).order_by('-id')

        if search != '':
            queryset = queryset.filter(Q(name__contains=search) | Q(url__contains=search))

        if node != '':
            queryset = queryset.filter(relation=node)

        pagination_queryset = self.paginate_queryset(queryset)
        serializer = self.get_serializer(pagination_queryset, many=True)
        return self.get_paginated_response(serializer.data)

    @method_decorator(request_log(level='INFO'))
    def add(self, request):
        """
        新增一个接口
        """

        api = Format(request.data)
        api.parse()

        api_body = {
            'name': api.name,
            'body': api.testcase,
            'url': api.url,
            'method': api.method,
            'project': models.Project.objects.get(id=api.project),
            'relation': api.relation
        }
        if models.API.objects.filter(name=api.name).filter(project=api.project):
            return Response(response.API_NAME_EXIST)
        try:
            models.API.objects.create(**api_body)
        except DataError:
            return Response(response.DATA_TO_LONG)

        return Response(response.API_ADD_SUCCESS)

    @method_decorator(request_log(level='INFO'))
    def update(self, request, **kwargs):
        """
        更新接口
        """
        pk = kwargs['pk']
        api = Format(request.data)
        api.parse()

        api_body = {
            'name': api.name,
            'body': api.testcase,
            'url': api.url,
            'method': api.method,
        }

        raw_objs = models.API.objects.filter(name=api.name)
        if raw_objs and raw_objs[0].id != int(pk):
            return Response(response.API_NAME_EXIST)
        try:
            models.API.objects.filter(id=pk).update(**api_body)
        except ObjectDoesNotExist:
            return Response(response.API_NOT_FOUND)

        return Response(response.API_UPDATE_SUCCESS)

    @method_decorator(request_log(level='INFO'))
    def copy(self, request, **kwargs):
        """
        pk int: test id
        {
            name: api name
        }
        """
        pk = kwargs['pk']
        name = request.data['name']
        api = models.API.objects.get(id=pk)
        body = eval(api.body)
        body["name"] = name
        api.body = body
        api.id = None
        api.name = name
        if models.API.objects.filter(name=name).filter(project=api.project):
            return Response(response.API_NAME_EXIST)
        else:
            api.save()
            return Response(response.API_ADD_SUCCESS)

    @method_decorator(request_log(level='INFO'))
    def delete(self, request, **kwargs):
        """
        删除一个接口 pk
        删除多个
        [{
            id:int
        }]
        """

        try:
            if kwargs.get('pk'):  # 单个删除
                api_end(kwargs['pk'])
            else:
                for content in request.data:
                    api_end(content['id'])

        except ObjectDoesNotExist:
            return Response(response.API_NOT_FOUND)

        return Response(response.API_DEL_SUCCESS)

    @method_decorator(request_log(level='INFO'))
    def single(self, request, **kwargs):
        """
        查询单个api，返回body信息
        """
        try:
            api = models.API.objects.get(id=kwargs['pk'])
        except ObjectDoesNotExist:
            return Response(response.API_NOT_FOUND)

        parse = Parse(eval(api.body))
        parse.parse_http()

        resp = {
            'id': api.id,
            'body': parse.testcase,
            'success': True,
        }
        return Response(resp)

    @method_decorator(request_log(level='INFO'))
    def upload(self, request):
        """
        上传API
        """
        # 项目ID
        project_id = request.POST.get("project")
        # 节点ID
        node_id = request.POST.get("nodeId")
        # 获取前端传输的文件对象
        file_obj = request.FILES.get('file')
        # 获取文件类型
        fileName = file_obj.name
        raw_name = fileName[:fileName.rfind('.')]
        file_type = fileName[fileName.rfind('.'):]
        file_name = raw_name + "_" + str(int(time.time()))  # 给上传的har文件名加一个时间戳
        har_file = file_name + file_type
        # 将HAR文件内容写入到本地
        basepath = os.path.join(MEDIA_ROOT, 'apidatas')
        if not os.path.exists(basepath):
            os.makedirs(basepath)
        har_path = os.path.join(basepath, har_file)
        with open(har_path, "wb+") as fp:
            for chunk in file_obj.chunks():
                fp.write(chunk)
        # 调用系统命令，将har文件转成测试用例
        cmd = 'har2case {har_path} -2j --exclude ".woff|.js|.css|.png|.jpg|.gif"'.format(har_path=har_path)
        resp = decode(subprocess.check_output(cmd, stderr=subprocess.STDOUT, timeout=60))
        if "Generate JSON testcase successfully" in resp:
            # 解析JSON，自定义转换格式，然后入库
            json_path = os.path.join(basepath, file_name + ".json")
            import_api_data(json_path, project_id, node_id)
        return Response(response.API_IMPORT_SUCCESS)

    @method_decorator(request_log(level='INFO'))
    def file(self, request):
        """
        上传API-File
        """
        # 获取前端传输的文件对象
        file_obj = request.FILES.get('file')
        # 获取文件类型
        fileName = file_obj.name
        raw_name = fileName[:fileName.rfind('.')]
        file_type = fileName[fileName.rfind('.'):]
        file_name = raw_name + "_" + str(int(time.time())) + file_type  # 给上传的文件名加一个时间戳
        # 将文件内容写入到本地
        basepath = os.path.join(MEDIA_ROOT, 'apidatas')
        if not os.path.exists(basepath):
            os.makedirs(basepath)
        file_path = os.path.join(basepath, file_name)
        with open(file_path, "wb+") as fp:
            for chunk in file_obj.chunks():
                fp.write(chunk)
        return Response({"code": 1001, "success": True, "msg": "文件上传成功!", "url": file_name})


def decode(s):
    try:
        return s.decode('utf-8')
    except UnicodeDecodeError:
        return s.decode('gbk')
